package bancosys.tec.persist.traverse.visitor;

import java.util.Collection;
import java.util.Map;

import jmine.tec.persist.PersistMessages;

import org.hibernate.LockMode;
import org.hibernate.SessionFactory;

import bancosys.tec.persist.Persistable;
import bancosys.tec.persist.traverse.PersistableVisitor;
import bancosys.tec.utils.traverser.TraverseException;

/**
 * Visitor que reassocia objeto com a sessão
 * 
 * @author pedro
 */
public class ReassociateObjectVisitor extends PersistableVisitor {
    private SessionFactory sessionFactory;

    /**
     * Método que reassocia um persistable com a sessão
     * 
     * @param persistable objeto a ser reassociado
     * @throws TraverseException não é lançada
     */
    @Override
    protected void visit(Persistable persistable) throws TraverseException {
        this.lock(persistable);
    }

    /**
     * Não há comportamento esperado para um tipo não persistable
     * 
     * @param unknown objeto de tipo desconhecido
     * @throws TraverseException sempre é lançada
     */
    @Override
    protected void visitUnknown(Object unknown) throws TraverseException {
        throw new TraverseException(PersistMessages.TRAVERSE_UNKNOWN.create());
    }

    /**
     * Devolve a {@link SessionFactory}
     * 
     * @return a {@link SessionFactory}
     */
    public SessionFactory getSessionFactory() {
        return this.sessionFactory;
    }

    /**
     * Define a {@link SessionFactory}
     * 
     * @param sessionFactory a {@link SessionFactory}
     */
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    /**
     * Método que reassocia uma collection com a sessão
     * 
     * @param collection objeto a ser reassociado
     * @throws TraverseException não é lançada
     */
    @Override
    protected void visit(Collection<?> collection) throws TraverseException {
        this.lock(collection);
    }

    /**
     * Método que reassocia uma collection com a sessão
     * 
     * @param map objeto a ser reassociado
     * @throws TraverseException não é lançada
     */
    @Override
    protected void visit(Map<?, ?> map) throws TraverseException {
        this.lock(map);
    }

    /**
     * Método que reassocia uma collection com a sessão
     * 
     * @param array objeto a ser reassociado
     * @throws TraverseException não é lançada
     */
    @Override
    protected void visitArray(Object array) throws TraverseException {
        this.lock(array);
    }

    /**
     * Trava o objeto na sessão
     * 
     * @param object objeto a ser colocado na sessão
     */
    private void lock(Object object) {
        this.getSessionFactory().getCurrentSession().lock(object, LockMode.NONE);
    }

}
